Clique abaixo para selecionar qual deseja visualizar.
Este estudo buscou analisar o comportamento do IFIX. Para tal, foram coletados dados históricos de janeiro de 2015 à setembro de 2023. Adicionalmente, foi explorado correlação com os índices IBOV, Selic e IPCA. Posteriormente, utilizou-se o modelo estatístico ARIMA que combina elementos de autocorrelação (AR) e médias móveis (MA) para capturar padrões temporais nos dados. Concluiu-se que um período maior e intervalos menores, forneceria robustez a estudos futuros. Evidencia-se esta afirmativa em virtude do contexto vivido no período em questão, múltiplos governos, impeachment, pandemia, amplitude da taxa Selic, crises… Ainda assim, o modelo ARIMA identificou tendências e padrões de predição, passível de se observar ao analisar experimento “out-of-sample”. Ademais, independentemente, o presente trabalho cumpriu com êxito seus objetivos. Orientado sob viés didático, exploratório, especulativo e a fim de demonstrar repertório do autor acerca dos temas em questão.
Assume-se que um bom investimento é realizado no lugar, momento e valor adequado. Propôs-se aqui debruçar-se sobre o comportamento do IFIX (Índice de Fundos de Investimentos Imobiliários) com caráter exploratório a fim de analisar a intrínseca relação desse índice.
Para tal, analisou-se correlação com outros índices. Em particular IBOV (ou IBOVESPA - Índice da Bolsa de Valores de São Paulo), Selic (Sistema Especial de Liquidação e Custódia) e IPCA (Índice Nacional de Preços ao Consumidor Amplo). O período analisado foi de janeiro de 2015 à setembro de 2023, com intervalo mensal.
Em um segundo momento utilizou-se o modelo estatístico ARIMA que combina elementos de autocorrelação (AR) e médias móveis (MA) para capturar padrões temporais nos dados.
Possui como objetivos gerais:
Possui como objetivos específicos:
O banco de dados foi formado com suas fontes, os índices Selic e IPCA
cedidos pelo BACEN (Banco Central do Brasil) e os índices IFIX e IPCA
foram coletados pela biblioteca TvDataFeed que possui como
fonte o site da TradingView. Mais detalhes sobre a metodologia
podem ser obtidos no tópico Replicabilidade e ao longo
do próprio trabalho.
“O presente material (…) não se trata de recomendação de compra ou venda de ativos e produtos financeiros. Qualquer decisão de investimento deve ser realizada por meio de aconselhamento profissional e personalizado, levando em consideração os objetivos, necessidades e situação financeira específica de cada investidor.”
(Orientação sobre divulgação de informações sobre investimentos. Comissão de Valores Mobiliários - CVM)
Para exibir as bibliotecas e ferramentas utilizadas clique no botão:
Bibliotecas R:
library(tidyverse)
library(plotly)
library(lubridate)
library(tibble)
library(jsonlite)
library(httr)
library(reticulate)
library(dplyr)
library(tseries)
library(forecast)Bibliotecas Python:
Tenha, como exemplo, a linha de código httr::GET(url).
Embora seja desnecessária a referência httr:: ela foi
explicitada ao longo do presente trabalho por motivos pessoais e de boas
práticas, como organização e referenciação da origem da função
utilizada.
Neste tópico foram detalhadas as versões para possibilitar replicação
dos resultados obtidos. Para mais detalhes, clique no botão:
Caso queira replicar, certifique-se de ter os pacotes necessários rodando o seguinte código:
library <- c("tidyverse",
"plotly",
"lubridate",
"tibble",
"jsonlite",
"httr",
"reticulate",
"dplyr",
"tseries",
"forecast")
if (sum(as.numeric(!library %in% installed.packages())) != 0) {
instalador <- library[!library %in% installed.packages()]
for (i in 1:length(instalador)) {
install.packages(instalador, dependencies = T)
break()}
sapply(library, require, character = T)
} else {
sapply(library, require, character = T)
}## tidyverse plotly lubridate tibble jsonlite httr reticulate
## TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## dplyr tseries forecast
## TRUE TRUE TRUE
Foi também utilizado a versão forked do TvDataFeed, para instalar:
!pip install --upgrade --no-cache-dir git+https://github.com/rongardF/tvdatafeed.git
A versão do R, Python e Reticulate.
pver = (__import__('sys').version)[0:6]
print(" Reticulate version", r.rrtver,"\n Python version", pver,"\n", r.rver)## Reticulate version 1.32.0
## Python version 3.9.16
## R version 4.3.1 (2023-06-16)
Os pacotes e versões utilizadas foram:
pckgver <- for (package_name in sort(loadedNamespaces())) {print(paste(package_name, packageVersion(package_name)))}## [1] "base 4.3.1"
## [1] "bslib 0.5.0"
## [1] "cachem 1.0.8"
## [1] "cli 3.6.1"
## [1] "colorspace 2.1.0"
## [1] "compiler 4.3.1"
## [1] "curl 5.0.0"
## [1] "data.table 1.14.8"
## [1] "datasets 4.3.1"
## [1] "digest 0.6.33"
## [1] "dplyr 1.1.3"
## [1] "evaluate 0.21"
## [1] "fansi 1.0.4"
## [1] "fastmap 1.1.1"
## [1] "forcats 1.0.0"
## [1] "forecast 8.21.1"
## [1] "fracdiff 1.5.2"
## [1] "generics 0.1.3"
## [1] "ggplot2 3.4.2"
## [1] "glue 1.6.2"
## [1] "graphics 4.3.1"
## [1] "grDevices 4.3.1"
## [1] "grid 4.3.1"
## [1] "gtable 0.3.3"
## [1] "here 1.0.1"
## [1] "hms 1.1.3"
## [1] "htmltools 0.5.6"
## [1] "htmlwidgets 1.6.2"
## [1] "httr 1.4.6"
## [1] "jquerylib 0.1.4"
## [1] "jsonlite 1.8.7"
## [1] "knitr 1.43"
## [1] "lattice 0.21.8"
## [1] "lazyeval 0.2.2"
## [1] "lifecycle 1.0.3"
## [1] "lmtest 0.9.40"
## [1] "lubridate 1.9.2"
## [1] "magrittr 2.0.3"
## [1] "Matrix 1.6.0"
## [1] "methods 4.3.1"
## [1] "munsell 0.5.0"
## [1] "nlme 3.1.162"
## [1] "nnet 7.3.19"
## [1] "parallel 4.3.1"
## [1] "pillar 1.9.0"
## [1] "pkgconfig 2.0.3"
## [1] "plotly 4.10.2"
## [1] "png 0.1.8"
## [1] "purrr 1.0.2"
## [1] "quadprog 1.5.8"
## [1] "quantmod 0.4.25"
## [1] "R6 2.5.1"
## [1] "Rcpp 1.0.11"
## [1] "readr 2.1.4"
## [1] "reticulate 1.32.0"
## [1] "rlang 1.1.1"
## [1] "rmarkdown 2.23"
## [1] "rprojroot 2.0.3"
## [1] "rstudioapi 0.14"
## [1] "sass 0.4.7"
## [1] "scales 1.2.1"
## [1] "stats 4.3.1"
## [1] "stringi 1.7.12"
## [1] "stringr 1.5.0"
## [1] "tibble 3.2.1"
## [1] "tidyr 1.3.0"
## [1] "tidyselect 1.2.0"
## [1] "tidyverse 2.0.0"
## [1] "timechange 0.2.0"
## [1] "timeDate 4022.108"
## [1] "tools 4.3.1"
## [1] "tseries 0.10.54"
## [1] "TTR 0.24.3"
## [1] "tzdb 0.4.0"
## [1] "urca 1.3.3"
## [1] "utf8 1.2.3"
## [1] "utils 4.3.1"
## [1] "vctrs 0.6.3"
## [1] "viridisLite 0.4.2"
## [1] "withr 2.5.0"
## [1] "xfun 0.40"
## [1] "xts 0.13.1"
## [1] "yaml 2.3.7"
## [1] "zoo 1.8.12"
Por fim, fixando a seed para valor fixos/replicáveis em eventual geração aleatória.
Para exibir detalhes sobre a aquisição dos Data Frames
clique no botão:
Definição inicial dos parâmetros:
Caso seja necessário, importe credenciais de um arquivo *.json para o ambiente Python.
# Definição do Usuário/Senha (Para aquisição do IBOV e IFIX).
#tradingview <- jsonlite::fromJSON("tradingview.json")
#py$username <- tradingview$username
#py$password <- tradingview$passwordA biblioteca TvDataFeed permite realizar consultas sem
estar logado, contudo terá limitação em determinadas requisições. Embora
neste trabalho não tenha sido necessário Login, foi
disponibilizado, no código acima, a possibilidade de realizar login
apartir de um arquivo json contendo usuário e senha.
As principais bibliotecas (como
quantmod,tidyquant,BatchGetSymbols,
investpy, …) “puxam” dados do Yahoo Finance, que
são incompletos para o índice do IFIX. Também, algumas dessas
bibliotecas foram descontinuadas como é o caso do Google
Finance em março de 2018, e o site Investing. Alpha
Vantage também não é uma opção viável. Com isto em mente, a seguir
foi utilizada a biblioteca fork do TvDataFeed que
recebe dados do site TradingView. Nesta parte será utilizado
Python, e posteriormente retornado para R.
## you are using nologin method, data you access may be limited
Para este estudo em particular não é necessário login como citado anteriormente.
Os índices a seguir foram adquiridos por meio de requisição pela API do BACEN (Banco Central do Brasil):
https://api.bcb.gov.br/dados/serie/bcdata.sgs.{codigo_serie}/dados?formato=json&dataInicial={dataInicial}&dataFinal={dataFinal}
Para maiores detalhes cheque a seção Referências.
# Parâmetros iniciais para aquisição do IPCA e Selic.
dataInicial <- "01/01/2015"
dataFinal <- "01/09/2023"
formato <- "json"
cod_ipca <- "10844"
cod_selic <- "4390"Definindo caminho:
ipca_url <- sprintf("https://api.bcb.gov.br/dados/serie/bcdata.sgs.%s/dados?formato=%s&dataInicial=%s&dataFinal=%s", cod_ipca, formato, dataInicial, dataFinal)
cat(ipca_url)## https://api.bcb.gov.br/dados/serie/bcdata.sgs.10844/dados?formato=json&dataInicial=01/01/2015&dataFinal=01/09/2023
Realizando requisição e transformando conteúdo _*.json_ em DataFrame para ser trabalhado:
Definindo caminho:
selic_url <- sprintf("https://api.bcb.gov.br/dados/serie/bcdata.sgs.%s/dados?formato=%s&dataInicial=%s&dataFinal=%s", cod_selic, formato, dataInicial, dataFinal)
cat(selic_url)## https://api.bcb.gov.br/dados/serie/bcdata.sgs.4390/dados?formato=json&dataInicial=01/01/2015&dataFinal=01/09/2023
Realizando requisição e transformando conteúdo _*.json_ em DataFrame para ser trabalhado:
O presente trabalho trabalhou com quatro Data Frames, contendo dados sobre índices IFIX, IBOV, IPCA e Selic. Organizado temporalmente em intervalo de meses. Os dados “crús” podem ser visualizados logo abaixo:
Clique acima para selecionar qual deseja visualizar.
A limpeza e padronização foi realizada da seguinte forma:
open).Por fim, os dados foram consolidados em uma tabela única como exibido abaixo:
Neste momento foi realizado a limpeza e padronização dos dados.
Clique acima para selecionar qual deseja visualizar.
# Index (data) para coluna
ifix_df$timestamp <- row.names(ifix_df)
# Formatando data e padronizando dias para 01 ("normalizando" dias úteis)
ifix_df$timestamp <- as.Date(ifix_df$timestamp, format = "%Y-%m-%d")
ifix_df$timestamp <- lubridate::floor_date(ifix_df$timestamp, unit = "month") + days(0)
# Resetando numeração da coluna (index)
ifix_df <- data.frame(ifix_df, row.names = NULL)
# Transformando valores em variações percentuais
ifix_df <- dplyr::mutate(ifix_df, IFIX = ((ifix_df$open - lag(ifix_df$open, default = dplyr::first(ifix_df$open)))/lag(ifix_df$open, default = dplyr::first(ifix_df$open))) * 100)
# Selecionando colunas de interesse
ifix_df <- subset(ifix_df, select = c(timestamp, IFIX))
# Excluindo primeira linha de 12/2014
ifix_df <- dplyr::slice(ifix_df, -1)
# Arredondando decimais para duas casas
ifix_df$IFIX <- round(ifix_df$IFIX, 2)
# Transformando em Tibble Data Frame
ifix_df <- as_tibble(ifix_df)A variação foi obtida através da fórmula: \[Variação = \dfrac {Valor Posterior- Valor Anterior}{Valor Anterior} \times 100\] Após padronização, temos:
# Index (data) para coluna
ibov_df$timestamp <- row.names(ibov_df)
# Formatando data e padronizando dias para 01 ("normalizando" dias úteis)
ibov_df$timestamp <- as.Date(ibov_df$timestamp, format = "%Y-%m-%d")
ibov_df$timestamp <- lubridate::floor_date(ibov_df$timestamp, unit = "month") + days(0)
# Resetando numeração da coluna (index)
ibov_df <- data.frame(ibov_df, row.names = NULL)
# Transformando valores em variações percentuais
ibov_df <- dplyr::mutate(ibov_df, IBOV = ((ibov_df$open - lag(ibov_df$open, default = dplyr::first(ibov_df$open)))/lag(ibov_df$open, default = dplyr::first(ibov_df$open))) * 100)
# Selecionando colunas de interesse
ibov_df <- subset(ibov_df, select = c(timestamp, IBOV))
# Excluindo primeira linha de 12/2014
ibov_df <- dplyr::slice(ibov_df, -1)
# Arredondando decimais para duas casas
ibov_df$IBOV <- round(ibov_df$IBOV, 2)
# Transformando em Tibble Data Frame
ibov_df <- as_tibble(ibov_df)A variação foi obtida através da fórmula: \[Variação = \dfrac {Valor Posterior- Valor Anterior}{Valor Anterior} \times 100\] Após padronização, temos:
# Renomeando coluna
names(ipca_df) <- c("timestamp", "IPCA")
# Padronizando formatação da datação
ipca_df$timestamp <- as.Date(ipca_df$timestamp, format = "%d/%m/%Y")
# Alterando classe <cha> para <dbl>
ipca_df$IPCA <- as.numeric(ipca_df$IPCA)
# Transformando em Tibble Data Frame
ipca_df <- as_tibble(ipca_df)Após padronização, temos:
# Renomeando coluna
names(selic_df) <- c("timestamp", "Selic")
# Padronizando formatação da datação
selic_df$timestamp <- as.Date(selic_df$timestamp, format = "%d/%m/%Y")
# Alterando classe <cha> para <dbl>
selic_df$Selic <- as.numeric(selic_df$Selic)
# Transformando em Tibble Data Frame
selic_df <- as_tibble(selic_df)Após padronização, temos:
combined_df <- ifix_df %>%
left_join(ibov_df, by = "timestamp") %>%
left_join(ipca_df, by = "timestamp") %>%
left_join(selic_df, by = "timestamp")
combined_df## [1] NA NA NA
## [1] 0.60 1.41 0.25 0.52 -0.06 0.62 0.25 0.08 NA NA
# Exclusão das duas últimas linhas (setembro/outrubro)
df_sem_ultima_linha <- combined_df[1:(nrow(combined_df) - 2), ]
tail(df_sem_ultima_linha$IPCA,10)## [1] 0.13 0.44 0.60 1.41 0.25 0.52 -0.06 0.62 0.25 0.08
Os dados, agora padronizados, são exibidos em for gráfica logo abaixo. O gráfico das variações exibe apenas as ocilações e poucas informações oferece de forma isolada. Logo em seguida, através de uma soma acumulada das variações, um gráfico representando melhor o intervalo foi elaborado.
Os gráficos são interativos, é possível isolar períodos ao clicar, segurar e arrastar pelos intervalos desejados. Ou deixar mouse em cima do mês de interesse para que seja exibido detalhes em uma etiqueta que surgirá.
Clique acima para selecionar qual deseja visualizar.
plot_var <- plot_ly(data = combined_df, x = ~timestamp, type = "scatter",
y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~IBOV, mode = "lines", name = "IBOV") %>%
add_trace(y = ~IPCA, mode = "lines", name = "IPCA") %>%
add_trace(y = ~Selic, mode = "lines", name = "Selic") %>%
layout(title = "Variações do Período",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 9, gridcolor = "#303030"),
yaxis = list(title = "Variação (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#d62728","#33a02c")
)
plot_var# Soma acumulada das variações
acum_df <- combined_df
acum_df$IFIX <- cumsum(acum_df$IFIX)
acum_df$IBOV <- cumsum(acum_df$IBOV)
acum_df$IPCA <- cumsum(acum_df$IPCA)
acum_df$Selic <- cumsum(acum_df$Selic)plot_acum <- plot_ly(data = acum_df, x = ~timestamp, type = "scatter",
y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~IBOV, mode = "lines", name = "IBOV") %>%
add_trace(y = ~IPCA, mode = "lines", name = "IPCA") %>%
add_trace(y = ~Selic, mode = "lines", name = "Selic") %>%
layout(title = "Variação Acumulada do Período",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 9, gridcolor = "#303030"),
yaxis = list(title = "Rendimento (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#d62728","#33a02c")
)
plot_acumLeia sobre a Análise Gráfica realizada clicando no botão:
No período o IFIX apresenta uma volatilidade considerável
(mínima de -15 à máxima de 10 ), talvez tenha
sido tão grande devido mudanças de governo (momentos súbitos e
dicotômicos de Selic alta/baixa) e principalmente pandemia. O IBOV é
conhecidamente um índice volátil por representar ações, no obstante, o
afirmado sobre IFIX possivelmente aplica-se aqui também.
A média do IFIX neste período foi uma surpresa, pois é
superior a média IBOV. Dessa forma, demonstrando ser preferível no
quesito “rentabilidade”, especialmente se julgar a questão da segurança,
onde a oscilação do IFIX é inferior ao IBOV. Adicionalmente, esse
argumento é suportado pelos dados apresentados nos quartis.
Isto é, volatilidade menor, supostamente maior “segurança”. Embora tais
afirmativas acerca da análises sejam limitadas, devido intervalo mensal,
esta problemática foi melhor abordada no tópico Considerações
Finais.
A mínima do IPCA ser negativa implica deflação e,
objetivamente, um possível momento de superação de uma crise ou momento
de grande incerteza/variabilidade.
Em termos de amostral e representatividade, existem duas posturas diametralmente opostas a se refletir:
## IFIX IBOV IPCA Selic
## Min. :-15.8500 Min. :-29.970 Min. :-0.4700 Min. :0.1300
## 1st Qu.: -0.8650 1st Qu.: -3.120 1st Qu.: 0.1950 1st Qu.:0.4700
## Median : 1.0300 Median : 0.840 Median : 0.3900 Median :0.7300
## Mean : 0.9073 Mean : 1.099 Mean : 0.4062 Mean :0.7154
## 3rd Qu.: 2.6150 3rd Qu.: 6.035 3rd Qu.: 0.6200 3rd Qu.:1.0550
## Max. : 10.6300 Max. : 16.960 Max. : 1.4100 Max. :1.2200
Para melhor analisar o comportamento desses índices, a seguir foi realizado uma análise de correlação (Correlação de Pearson).
Para realizar o cálculo de correlação, primeiramente será considerado
período de doze meses. Isto é, “nos ultimos 12 meses a taxa do índice
x foi y…”.
Leia sobre a Análise de Correlação realizada clicando
no botão:
Definindo data frame com a somatória acumulada do último ano. Obviamente os valores dos primeiros meses apenas consideram eles mesmo, dessa forma os primeiros meses têm valores inferiores ao intervalo de 12 meses. Mas isso não interfere neste cálculo, pois considera apenas a interação entre eles.
# Data frame contendo valores do ultimo ano.
l12df <- combined_df %>%
mutate(across(c(IFIX, IBOV, IPCA, Selic),
~ cumsum(.) - lag(cumsum(.), n = 12, default = 0)))
l12dfDessa forma, abaixo a representação gráfica da variação acumulada móvel do período:
plot_last12 <- plot_ly(data = l12df, x = ~timestamp, type = "scatter",
y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~IBOV, mode = "lines", name = "IBOV") %>%
add_trace(y = ~IPCA, mode = "lines", name = "IPCA") %>%
add_trace(y = ~Selic, mode = "lines", name = "Selic") %>%
layout(title = "Variação Acumulada Móvel com Intervalo de 12 meses",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 9, gridcolor = "#303030"),
yaxis = list(title = "Variação (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#d62728","#33a02c")
)
plot_last12O gráfico acima, aparentemente conta uma história, especialmente se focarmos nos índices Selic. Se observamos, à princípio, logo após uma estabilização ou queda da Selic, o IFIX e IBOV valorizam (período de 2017 à 2022). Por outro lado, em um movimento de alta da Selic (período de 2015 à 2016 e novamente de 2022 à 2023) houve desvalorização do IFIX e IBOV.
Embora com o gráfico acima seja possível hipotetizar a afirmativa anterior, qualquer investidor minimamente estudado certamente já concluiu o mesmo. Abaixo foi calculado a grandeza dessa correlação.
# Excluindo duas últimas linhas devido dado faltante do IPCA.
l12df_sem_ultima_linha <- l12df[1:(nrow(l12df) - 2), ]
# Realizando cálculo da correlação
l12cor <- cor(l12df_sem_ultima_linha[, c("IFIX", "IBOV", "IPCA", "Selic")])
l12cor## IFIX IBOV IPCA Selic
## IFIX 1.0000000 0.63192296 0.1043657 0.44200095
## IBOV 0.6319230 1.00000000 -0.2823617 -0.02893405
## IPCA 0.1043657 -0.28236169 1.0000000 0.81675913
## Selic 0.4420010 -0.02893405 0.8167591 1.00000000
heatmap_l12 <- plot_ly(
type = "heatmap",
colorscale = "Portland",
z = l12cor,
x = colnames(l12cor),
y = rownames(l12cor),
zmin = -1,
zmax = 1,
reversescale = TRUE
) %>% layout(
title = "Matriz de Correlação",
font = list(color = '#FFFFFF'),
paper_bgcolor = "#222222",
showlegend = FALSE
)
# Exibindo anotações no gráfico onde valor diferente de 1.
for (nr in 1:nrow(l12cor)) {
for (nc in 1:ncol(l12cor)) {
if (l12cor[nr, nc] != 1) {
heatmap_l12 <- heatmap_l12 %>%
add_annotations(
text = round(l12cor[nr, nc], 6),
x = colnames(l12cor)[nc],
y = rownames(l12cor)[nr],
showarrow = FALSE,
font = list(size = 14, color = "white"))}}}
heatmap_l12A relação IFIX x IBOV (0.64) exibe uma
moderada correlação e positiva. Sugerindo que tendem a se mover na mesma
direção juntos, embora a forma não seja perfeitamente linear.
A relação IPCA x Selic (0.82) exibe uma
alta correlação e positiva. O que é esperado já que uma das funçãos da
Selic é justamente controlar a inflação.
Tendo em mente o periodo amostral selecionado (de 2015 à 2023) ser possivelmente pequeno e principalmente intervalo (mensal) ser pequeno, pode ter ocasionado nessa aparente “ausência de expressividade” nas correlações calculadas.
Para exibir a análise clique no botão:
Checando dados:
## [1] 2.69 -0.27 -1.62 3.68 1.47 3.03 0.70 -0.87 -3.94 2.13
## [11] 1.58 -3.01 -6.11 2.88 9.16 4.61 3.74 1.60 5.97 1.80
## [21] 2.77 3.85 -2.59 1.50 3.75 4.87 0.19 0.15 1.03 0.84
## [31] -0.38 0.87 6.57 0.23 -0.59 0.60 2.64 1.14 2.00 -0.86
## [41] -5.27 -4.02 1.39 -0.71 -0.22 5.04 2.59 2.22 2.47 1.03
## [51] 1.99 1.03 1.76 2.87 1.28 -0.11 1.04 4.01 3.52 10.63
## [61] -3.76 -3.69 -15.85 4.39 2.08 5.59 -2.60 1.79 0.46 -1.01
## [71] 1.52 2.18 0.32 0.25 -1.38 0.51 -1.54 -2.20 2.51 -2.63
## [81] -1.24 -1.47 -3.64 8.78 -0.99 -1.29 1.42 1.19 0.26 -0.88
## [91] 0.66 5.76 0.49 0.02 -4.15 0.00 -1.60 -0.45 -1.69 3.52
## [101] 5.43 4.71 1.33
## Warning in adf.test(df_sem_ultima_linha$IFIX): p-value smaller than printed
## p-value
##
## Augmented Dickey-Fuller Test
##
## data: df_sem_ultima_linha$IFIX
## Dickey-Fuller = -4.736, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
Utilizando o ADF Test temos:
Sendo o p-valor inverior a 0.05, rejeitamos a hipótese nula (H0). Sugerindo se tratar de uma série é estacionária.
Para exibir a análise clique no botão:
Checando melhores parâmetros para ARIMA.
## Series: df_sem_ultima_linha$IFIX
## ARIMA(0,0,3) with non-zero mean
##
## Coefficients:
## ma1 ma2 ma3 mean
## 0.1813 0.0472 -0.3458 0.8961
## s.e. 0.0908 0.0946 0.1015 0.2772
##
## sigma^2 = 10.38: log likelihood = -264.83
## AIC=539.65 AICc=540.27 BIC=552.83
Resultando em 0,0,3 (p,d,q ou
AR,I,MA).
Para exibir a análise clique no botão:
Com os parêmtros anteriores obtidos o modelo a seguir foi obtido:
##
## Call:
## arima(x = combined_df$IFIX, order = c(0, 0, 3))
##
## Coefficients:
## ma1 ma2 ma3 intercept
## 0.1820 0.0480 -0.3443 0.9009
## s.e. 0.0899 0.0937 0.1003 0.2727
##
## sigma^2 estimated as 9.788: log likelihood = -268.97, aic = 547.95
Para exibir a análise clique no botão:
Checando se os parâmetros são adequados. Isto é, se os resíduos se correlacionam com os parâmetros. Se eles se correlacionarem signica que não está adequado, pois tais resíduos deveriam ser aproveitados na previsão. Com outras palavras, testa o enviesamento dos parâmetros.
## Time Series:
## Start = 1
## End = 105
## Frequency = 1
## [1] 1.66547441 -1.35698763 -2.14142330 3.64430149 -0.43570629
## [6] 1.37393885 0.81280871 -2.12755146 -4.01777475 2.33561207
## [11] -0.28582471 -5.35094132 -5.21961199 3.08706585 6.10481560
## [16] 0.65275810 3.49044081 2.13449718 4.73789792 1.13613881
## [21] 2.17002242 4.13104095 -3.95577357 1.86831360 4.12127016
## [26] 1.76712332 -0.58692606 0.69033111 0.64011316 -0.41261261
## [31] -0.99874957 0.39116190 5.50375867 -2.03546477 -1.24965296
## [36] 1.91944034 0.74876706 -0.41955879 1.80053521 -1.81068311
## [41] -6.07208751 -3.10862022 0.72283569 -3.68419514 -1.55528121
## [46] 4.84790304 -0.38740500 0.62155062 3.14390137 -0.60640876
## [51] 1.26273494 1.01092628 0.40571532 2.28159249 0.29242580
## [56] -1.03384677 1.09895773 3.05936613 1.65348199 9.65978212
## [61] -5.44522311 -3.49363084 -12.52739687 4.06225113 -0.16241213
## [66] 0.21013286 -2.13252799 1.21134271 -0.48672410 -2.61468675
## [71] 1.53558607 0.95742304 -1.72916615 0.14675470 -1.89494990
## [76] -0.64836403 -2.18139688 -3.32516111 2.09584665 -4.50403139
## [81] -2.56646469 -0.96590460 -5.79283283 8.09628106 -3.41945072
## [86] -3.95147701 4.19039407 -1.46159776 -1.93646577 0.08469577
## [91] -0.66667577 4.30963171 -1.13426066 -1.11068402 -3.31027712
## [96] -0.63554086 -2.60882323 -1.98532103 -2.32314292 2.23896315
## [101] 3.54936359 2.25563565 0.61920833 0.59039642 -0.06133984
Tendo em vista que os
lag’s (os “picos” no gráfico) se
encontram dentro da banda de confiança (tracejado azul horizontal),
sugere que os resíduos não se correlacionam com o modelo. Isto é, o
modelo realizado captura os padrões nos dados.
## [1] -0.007488662
Nesta etapa foi checado se (em média) os erros de previsão não estão enviesados, acima ou abaixo do valor real. Se os residuos fossem diferentes de 0 sugeriria um enviesamento do modelo. Garantindo assim o comportamento de “ruído branco”.
Checando distribuição normal do resíduo:
É desejável o “bell-shape” de uma distribuição normal, sugerindo não haver enviesamento do resíduo.
Os testes anteriores sugere respectivamente que:
Adversamente temos box.test:
##
## Box-Pierce test
##
## data: res_ifix_mdl
## X-squared = 1.7771, df = 10, p-value = 0.9978
O p-valor de 99% indica que não há evidência estatisticamente significativa para rejeitar hipótese nula (H0: Não há autocorrelação nos lags considerados). Isto é, exibem independência estatística e modelo captura adequadamente os padrões.
Para exibir a análise clique no botão:
Neste tópico buscou-se predizer o ano de 2023 até setembro, e analisar esta possibilidade. Mas antes usou-se como métrica de comparação a predição que foi realizada a seguir no tópico 3.5.2 que tentará predizer os próximos dois anos a partir do intervalo entre 01/2015 e 09/2023
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 106 0.7048021 -3.304586 4.714190 -5.427028 6.836632
## 107 0.6946248 -3.380657 4.769907 -5.537981 6.927231
## 108 0.9219869 -3.157831 5.001805 -5.317557 7.161530
## 109 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 110 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 111 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 112 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 113 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 114 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 115 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 116 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 117 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 118 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 119 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 120 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 121 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 122 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 123 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 124 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 125 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 126 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 127 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 128 0.9008650 -3.406218 5.207948 -5.686250 7.487980
## 129 0.9008650 -3.406218 5.207948 -5.686250 7.487980
Ao prever 24 próximos meses, temos as seguintes colunas:
Point Forecast.Lo80 mínimo e Hi 80
máximo.Lo 95 mínimo e Hi 95
máximo.Neste momento abordaremos a contrastação com os dados já presentes e concretos do próprio ano de 2023. Isto é possível ser feito ao retirá-lo do amostral ou Out-of-Sample.
O raciocínio é simples: Se estivéssemos em dezembro de 2022, como seria o IFIX de 2023 utilizando esse modelo?
ifix15_22 <- arima(combined_df$IFIX[1:96], order = c(0,0,3))
forecast15_22 <- forecast(ifix15_22, h = 9)
forecast15_22## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 97 0.9986895 -3.112424 5.109803 -5.288717 7.286096
## 98 1.9862036 -2.179274 6.151681 -4.384345 8.356752
## 99 1.1037420 -3.064463 5.271947 -5.270978 7.478462
## 100 0.8790011 -3.514623 5.272625 -5.840467 7.598469
## 101 0.8790011 -3.514623 5.272625 -5.840467 7.598469
## 102 0.8790011 -3.514623 5.272625 -5.840467 7.598469
## 103 0.8790011 -3.514623 5.272625 -5.840467 7.598469
## 104 0.8790011 -3.514623 5.272625 -5.840467 7.598469
## 105 0.8790011 -3.514623 5.272625 -5.840467 7.598469
Avaliando precisão:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.007273949 3.207919 2.397492 Inf Inf 0.7728859 -0.01321303
O MAPE (Erro Percentual Absoluto Médio) sugere que, em média, as previsões têm um erro percentual absoluto médio de aproximadamente 198.12%. Já o modelo até 09/2023.
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.007488662 3.128542 2.353064 Inf Inf 0.7868008 -0.0069888
A piora do modelo de 2022 pode ter acontecido devido ano de eleição com grandes oscilações não-recorrentes.
Padronizando dados do previsto 2015~2022:
# Extraindo valores do forecast:
forecastibble <- tibble(
Point_Forecast = forecast15_22$mean,
Lo_80 = forecast15_22$lower[, "80%"],
Hi_80 = forecast15_22$upper[, "80%"],
Lo_95 = forecast15_22$lower[, "95%"],
Hi_95 = forecast15_22$upper[, "95%"])
# Criando linhas e adequando
b_row <- tibble(
Point_Forecast = rep(NA, 96),
Lo_80 = rep(NA, 96),
Hi_80 = rep(NA, 96),
Lo_95 = rep(NA, 96)
)
forecastibble <- bind_rows(b_row, forecastibble)
tail(forecastibble,10)Padronizando informações e consolidando para permitir visualização:
# Recriando data frame com datas e o ifix
ifix_pred <- subset(combined_df, select = c(timestamp, IFIX))
# Unindo o data frame com predições do ano de 2023
ifix_pred <- merge(ifix_pred, forecastibble, by = 0)
# Removendo index
ifix_pred$Row.names <- NULL
# Reorganizando em ordem crescente
ifix_pred <- ifix_pred %>%
arrange(as.Date(timestamp))
# Separando em dois dataframes para poder replicar valores do ifix até 12/2022
ifix_pred_slice_top <- slice(ifix_pred, 1:96)
ifix_pred_slice_bottom <- slice(ifix_pred, 97:105)
# Replicando valores de IFIX para demais colunas
ifix_pred_slice_top <- ifix_pred_slice_top %>%
mutate(
Point_Forecast = ifix_pred_slice_top$IFIX,
Lo_80 = ifix_pred_slice_top$IFIX,
Hi_80 = ifix_pred_slice_top$IFIX,
Lo_95 = ifix_pred_slice_top$IFIX,
Hi_95 = ifix_pred_slice_top$IFIX
)
# Unindo metades
ifix_pred <- rbind(ifix_pred_slice_top, ifix_pred_slice_bottom)
# Soma acumulada das variações
ifix_pred$IFIX <- cumsum(ifix_pred$IFIX)
ifix_pred$Prd <- round(cumsum(ifix_pred$Point_Forecast),2)
ifix_pred$L80 <- round(cumsum(ifix_pred$Lo_80),2)
ifix_pred$H80 <- round(cumsum(ifix_pred$Hi_80),2)
ifix_pred$L95 <- round(cumsum(ifix_pred$Lo_95),2)
ifix_pred$H95 <- round(cumsum(ifix_pred$Hi_95),2)
ifix_pred <- subset(ifix_pred, select = c(timestamp, IFIX, Prd, L80, H80, L95, H95))
ifix_predAnalisando previsão de forma gráfica:
plt_pred_ifix <- plot_ly(data = ifix_pred, x = ~timestamp, type = "scatter",
y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~Prd, mode = "lines", name = "Predito") %>%
add_trace(y = ~L80, mode = "lines", name = "Menor 80%") %>%
add_trace(y = ~H80, mode = "lines", name = "Maior 80%") %>%
add_trace(y = ~L95, mode = "lines", name = "Menor 95%") %>%
add_trace(y = ~H95, mode = "lines", name = "Maior 95%") %>%
add_ribbons(ymin = ~L80, ymax = ~H80, color = I("rgba(51, 160, 44, 0.3)"),
name = "Intervalo 80%", showlegend = FALSE) %>%
add_ribbons(ymin = ~L95, ymax = ~H95, color = I("rgba(214, 39, 40, 0.3)"),
name = "Intervalo 95%", showlegend = FALSE) %>%
layout(title = "Predição IFIX 2023",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 9, gridcolor = "#303030"),
yaxis = list(title = "Rendimento (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#33a02c",
"#33a02c","#d62728","#d62728","#d62728")
)
plt_pred_ifixAnalisando predito de forma gráfica exclusivamente no período proposto:
# Filtrando para iniciar a partir de dez/2022
ifix_pred_filter <- ifix_pred %>%
filter(row_number() >= 96)
# Criando o gráfico
f_plt_pred_ifix <- plot_ly(data = ifix_pred_filter, x = ~timestamp, type = "scatter",
y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~Prd, mode = "lines", name = "Predito") %>%
add_trace(y = ~L80, mode = "lines", name = "Menor 80%") %>%
add_trace(y = ~H80, mode = "lines", name = "Maior 80%") %>%
add_trace(y = ~L95, mode = "lines", name = "Menor 95%") %>%
add_trace(y = ~H95, mode = "lines", name = "Maior 95%") %>%
add_ribbons(ymin = ~L80, ymax = ~H80, color = I("rgba(51, 160, 44, 0.3)"),
name = "Intervalo 80%", showlegend = FALSE) %>%
add_ribbons(ymin = ~L95, ymax = ~H95, color = I("rgba(214, 39, 40, 0.3)"),
name = "Intervalo 95%", showlegend = FALSE) %>%
layout(title = "Predição IFIX 2023",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 1, gridcolor = "#303030"),
yaxis = list(title = "Rendimento (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#33a02c",
"#33a02c","#d62728","#d62728","#d62728")
)
f_plt_pred_ifixComo o modelo aqui desenvolvido, no intervalo entre 01/2015 e 12/2022, predisse o ano de 2023 até o mês de setembro?
A variação é grande pois quanto mais “no futuro”, maior a chance de erro, em outras palavras, “acumuladamente” o erro se dá. Outro grande fator, que se hipotetiza, é que as eleições de 2022 podem ter contribuído para uma maior oscilação não-recorrente do período observado.
No intervalo entre 01/2015 e 09/2023, como o modelo aqui desenvolvido predisse o intervalo de 10/2023 até 09/2025 ?
# Repetindo código para gerar predições
forecast_ifix <- forecast(ifix_mdl, h = 24)
# Extraindo valores do forecast:
forecast_ifix <- tibble(
Point_Forecast = forecast_ifix$mean,
Lo_80 = forecast_ifix$lower[, "80%"],
Hi_80 = forecast_ifix$upper[, "80%"],
Lo_95 = forecast_ifix$lower[, "95%"],
Hi_95 = forecast_ifix$upper[, "95%"])
forecast_ifix <- forecast_ifix %>%
mutate(timestamp = seq.Date(from = as.Date("2023-10-01"),
to = as.Date("2025-09-01"),
by = "month"))
# Recriando data frame com datas e o ifix
forecast_ifix_pred <- subset(combined_df, select = c(timestamp, IFIX))
# Replicando valores de IFIX para demais colunas
forecast_ifix_pred <- forecast_ifix_pred %>%
mutate(
Lo_80 = forecast_ifix_pred$IFIX,
Hi_80 = forecast_ifix_pred$IFIX,
Lo_95 = forecast_ifix_pred$IFIX,
Hi_95 = forecast_ifix_pred$IFIX
)
# Renomeando coluna para compatibilidade
forecast_ifix <- forecast_ifix %>%
rename(IFIX = Point_Forecast)
# Consolidando dados
forecast_ifix_pred <- rbind(forecast_ifix_pred, forecast_ifix)
# Soma acumulada das variações
forecast_ifix_pred$IFIX <- round(cumsum(forecast_ifix_pred$IFIX),2)
forecast_ifix_pred$L80 <- round(cumsum(forecast_ifix_pred$Lo_80),2)
forecast_ifix_pred$H80 <- round(cumsum(forecast_ifix_pred$Hi_80),2)
forecast_ifix_pred$L95 <- round(cumsum(forecast_ifix_pred$Lo_95),2)
forecast_ifix_pred$H95 <- round(cumsum(forecast_ifix_pred$Hi_95),2)
forecast_ifix_pred <- subset(forecast_ifix_pred, select = c(timestamp, IFIX, L80, H80, L95, H95))
forecast_ifix_predAnalisando previsão de forma gráfica:
plt_pred_25 <- plot_ly(data = forecast_ifix_pred, x = ~timestamp, type = "scatter",
y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~L80, mode = "lines", name = "Menor 80%") %>%
add_trace(y = ~H80, mode = "lines", name = "Maior 80%") %>%
add_trace(y = ~L95, mode = "lines", name = "Menor 95%") %>%
add_trace(y = ~H95, mode = "lines", name = "Maior 95%") %>%
add_ribbons(ymin = ~L80, ymax = ~H80, color = I("rgba(51, 160, 44, 0.3)"),
name = "Intervalo 80%", showlegend = FALSE) %>%
add_ribbons(ymin = ~L95, ymax = ~H95, color = I("rgba(214, 39, 40, 0.3)"),
name = "Intervalo 95%", showlegend = FALSE) %>%
layout(title = "Predição IFIX 2025",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 11, gridcolor = "#303030"),
yaxis = list(title = "Rendimento (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#33a02c",
"#33a02c","#d62728","#d62728","#d62728")
)
plt_pred_25Analisando predito de forma gráfica exclusivamente no período proposto:
# Filtrando para iniciar a partir de dez/2022
ifix_pred_filter_25 <- forecast_ifix_pred %>%
filter(row_number() >= 105)
# Criando o gráfico
f_plt_pred_ifix_25 <- plot_ly(data = ifix_pred_filter_25, x = ~timestamp, type = "scatter", y = ~IFIX, mode = "lines", name = "IFIX") %>%
add_trace(y = ~L80, mode = "lines", name = "Menor 80%") %>%
add_trace(y = ~H80, mode = "lines", name = "Maior 80%") %>%
add_trace(y = ~L95, mode = "lines", name = "Menor 95%") %>%
add_trace(y = ~H95, mode = "lines", name = "Maior 95%") %>%
add_ribbons(ymin = ~L80, ymax = ~H80, color = I("rgba(51, 160, 44, 0.3)"),
name = "Intervalo 80%", showlegend = FALSE) %>%
add_ribbons(ymin = ~L95, ymax = ~H95, color = I("rgba(214, 39, 40, 0.3)"),
name = "Intervalo 95%", showlegend = FALSE) %>%
layout(title = "Predição IFIX 2025",
font = list(color = "white"),
xaxis = list(title = "Data", nticks = 4, gridcolor = "#303030"),
yaxis = list(title = "Rendimento (valores em porcentagem)", gridcolor = "#303030"),
hovermode = "x unified",
paper_bgcolor = "#222222",
plot_bgcolor = "#222222",
colorway = c("#ff7f0e","#17becf","#33a02c",
"#33a02c","#d62728","#d62728","#d62728"))
f_plt_pred_ifix_25Assume-se que um bom investimento é realizado no lugar, momento e valor adequado. Neste tópico se propôs refletir sobre a interação dessas três variáveis, problemas e possíveis soluções implícitas.
O presente estudo teve como objetivo analisar o índice IFIX, suas correlações e possibilidade de predizer tendência baseado em dados desde janeiro de 2015 à setembro de 2023. Analisou correlações com outros índices do mercado, como IBOV, Selic e IPCA. Buscando em um primeiro momento correlações e posteriormente projetar tendência.
Uma grande parte do que se entende como “lucro” parte da premissa do momento. No caso de investimentos, pode ser melhor expressada pela “antecipação” deste momento. O presente trabalho não analisou a quase infinita míriade de possibilidades que impactam esse dito “momento”. Como por exemplo, reuniões do COPOM (Comitê de Política Monetária) que dita a previsão da taxa selic.
Sucintamente, uma diminuicão no gráfico da Selic (exposto no trabalho), meses antes já impactou nos índices de renda variável IFIX e IBOV. Em outras palavras, quedas abruptas “hoje” na renda variável talvez possam ser explicadas devido taxas elevadas previstas pelo COPOM nos “próximos meses”.
Ademais, tendo em vista a janela amostral (de sete anos) e seu intervalo (em meses), conclui-se que possui limitações em detrimento dessas variáveis. Adicionalmente há de se considerar contexto dos ultimos anos conturbados de pandemia, impeachment, trocas de governo e amplitude da taxa Selic. Uma janela maior e intervalos menores potencialmente abarcaria de forma mais adequada essa intrínseca conexão.
A íntrínseca conexão é possivel ser vista nesta variável. Como no final das eleições de 2022 ao tentar prever valores de 2023 (tópico 3.5.1). Com outras palavras, dinheiro só possui valor no tempo.
Por fim, cabe afirmar que o presente trabalho cumpriu com o objetivo de analisar sob caráter experimental e expeculativo. E, de certa forma, pode ser visto como um rascunho do que “pode ser feito”. Pois este, se trata apenas um mero exercício didático com fim de explorar e exibir repertório acerca dos conteúdos aqui abordados.
Índices IFIX e IBOV:
TvDataFeed (Mais detalhes: https://github.com/rongardF/tvdatafeed )
Índices IPCA e Selic
BACEN (Mais detalhes: https://www3.bcb.gov.br/sgspub/ )
IPCA https://dadosabertos.bcb.gov.br/dataset/10844-indice-de-precos-ao-consumidor-amplo-ipca---servicos
Selic https://dadosabertos.bcb.gov.br/dataset/4390-taxa-de-juros---selic-acumulada-no-mes